"""constants.py

Stores constant values for the combat system.

two classes are defined here:
enumerated -- used for the ElementTypes constant
bitmask -- used for the DT and EffectTypes constant
"""

__all__=["DT", "FX"]


class bitmask(object):
    """Simple bitmask object. Works like enumerated, but values
    are ordered for bitmasking"""
    def __init__(self, *args, **kw):
        self.__constants = {}
        for val, arg in enumerate(args):
            if val == 0: self.__default__ = arg.lower()
            self.__constants[arg.lower()] = pow(2,val)
            
        zero = kw.pop('zero',None)
        if zero:
            self.__constants[zero.lower()] = 0
        
        #~ if 'all' not in self.__constants:
            #~ self.__constants['all'] = self._next - 1

    @property
    def default(self):
        "returns the default value of enumeration"
        return self.__default__
    
    @property
    def last(self):
        "returns the last value used by the enumeration"
        return max(self.__constants.values())
    
    @property
    def _next(self):
        "returns the next available value for enumeration"
        return self.last * 2
    
    def __getattr__(self, att):
        att = att.lower()
        if att in self.__constants:
            return self.__constants[att]
        #~ elif att in self.__dict__:
            #~ return self.__dict__[att]
        elif att.lower() == 'all':
            return self._next - 1
        else:
            return None
    
    def __contains__(self, att):
        return att.lower() in self.__constants
    
    def __iter__(self):
        #~This is crazy, but it returns the list in order!
        return iter(sorted(self.__constants, key = self.__constants.__getitem__))
        
    
    def __getitem__(self, num):
        for k,v in self.__constants.iteritems():
            if v == num: return k
        raise ValueError, "Enumerated object does not have index %d" % (num)
    
    def __len__(self):
        return len(self.__constants)-1 #~ subtract the default value
    
    def name(self, i):
        try:
            return self[i]
        except ValueError:
            return None
    
    def add(self, name):
        name = name.lower()
        if name in self.__constants:
            raise ValueError, "cannot duplicate enumerated value %s" % name
        if name.lower == 'all':
            raise ValueError, "Cannot use 'ALL' as a value. Reserved bitmap word"
        self.__constants[name] = self._next
        
    
    def define(self, i):
        """Uses terms to generate a list of strings based on the number"""
        res = []
        for x in self.__constants: 
            if x == '__default__': continue
            if self.__constants[x] & i: res.append(x)
        return res
    
    def as_string(self, i):
        items = self.define(i)
        if len(items) == 0:
            return ""
        if len (items) == 1:
            return items[0]
        if len (items) == 2:
            return "%s and %s" % (items[0], items[1])
        return "%s, and %s" % (', '.join(items[:-1]), items[-1])
    
    def values(self):
        return self.__constants.values()
    
    def isvalue(self, number):
        return number in self.values()
        
DT = bitmask('crush', 'grapple',  'pierce', 'slash', 'life', 'magic', 
    'earth', 'air', 'fire', 'water', 'electricity', zero='none')
FX = bitmask('stun', 'trip', 'weak_poison', 'strong_poison', 'dodge', 'speedup', 'slowdown',
    'stronger', 'weaken', zero='none')
#~ EL = enumerated('none', 'earth', 'air', 'fire', 'water', 'electricity')







def test():
    #~ print EL
    #~ print dir(EL)
    #~ for elem in EL: 
        #~ print elem, getattr(EL, elem)
    #~ print EL[3], EL.name(3)
    #~ print EL._enumerated__constants
    #~ print len(EL)
    #~ print EL.default
    #~ print EL.last
    #~ EL.add('psi')
    #~ print len(EL)
    #~ print EL.psi
    #~ print 'psi' in EL
    #~ print EL._next
    
    
    #~ print DT
    #~ print DT.default
    #~ print dir(DT)
    #~ print DT._bitmask__constants
 
    #~ print DT.define(15)
    #~ print DT.last
    #~ print 'slash' in DT
    
    #~ for ty in DT: print ty, getattr(DT,ty)
        
    #~ print DT.last
    #~ print DT._next
    #~ DT.add('numb')
    #~ print DT.numb
    #~ print DT._next
    #~ print DT.default
    
    #~ print FX.default
    for f in FX: print f, getattr(FX, f), FX.name(getattr(FX, f) )
    print 'all', FX.all
    
    print 'DODGE' in FX, 'Dodge' in FX, 'dodge' in FX
    print FX.define(17)
    print FX.as_string(17)
    print FX.values()

    
if __name__=='__main__':
    #~ test()
    print DT.NONE
    print getattr(FX, 'weak_poison')
    print FX.values()
    print FX.isvalue(4)
    print FX.isvalue(5)